#pragma once

#include "Widgets/Widget.h"
#include "Scene/Scene.h"
#include "Containers/WeakObjectPtr.h"
#include "Widgets/Mouse/MouseWidget.h"
#include "Widgets/Keyboard/KeyboardWidget.h"

#include "Containers/ThreadSafePtr.h"
#include "Render/Scene/RenderScene.h"
#include "Render/Widget/VulkanViewportWidget.h"

#include "Render/Scene/CameraParameters.h"
#include "PixelObject/PixelObject.h"
#include "ViewportWidget.m.h"



class CVulkanViewportWidget;
class RViewportWidget;
class SRenderForegroundMeshInstance;
class RPixelObjectMap;
class CPixelObject;

RENUM()
enum class EViewportPaintMode
{
    None=0,              //什么也不绘制
    Scene=1<<0,          //绘制场景
    Foreground=1<<1,     //绘制前景,比如坐标轴
    Collision=1<<2,      //绘制碰撞体
};

//draw a scene
RCLASS()
class WHENGINE_API RViewportWidget: public RWidget
{
    ROBJECT
public:
    RViewportWidget();

    RFUNCTION()
    void SetScene(RScenePtr InScene);


protected:
    //the scene to paint
    RFIELD()
    TSharedObjectPtr<RScene> Scene;

    virtual void PaintSelf(uint16_t& InZOrder,const SRect& InClipArea) override;

    //used for scene accept mouse event 
    RFIELD()
    RMouseWidgetPtr Mouse;

    RFIELD()
    RKeyboardWidgetPtr Keyboard;

public:
    //default view port parameters 
    //will be used when Scene is null or bForceUseDefaultParameters is true
    TWidgetAttribute<SVec3> ViewportPosition;
    TWidgetAttribute<SQuat> ViewportRotation;

    TWidgetAttribute<float> AspectRatio=1920/1080.f;
    TWidgetAttribute<float> PerspectiveFOVY=45.f;
    
    TWidgetAttribute<EProjectionType> ProjectionType=EProjectionType::Perspective;

    TWidgetAttribute<float> OrthographicWidth=512.f;

    TWidgetAttribute<float> Near=0.1f;

    TWidgetAttribute<float> Far=100000.f;

    //if true, will use default parameters
    //if false, will get parameters from scene
    TWidgetAttribute<bool> bForceUseDefaultParameters=false;

    //获取上一次渲染的视角矩阵
    SMatrix4x4 GetLastViewMatrix() const
    {
        return LastParameters.ViewMatrix;
    }

    //获取上一次渲染的投影矩阵
    SMatrix4x4 GetLastProjectionMatrix() const
    {
        return LastParameters.ProjectionMatrix;
    }

    //将世界坐标转换为视口坐标,需要至少渲染一帧后才能生效
    SVec2 SceneToViewport(const SVec3& InScenePosition) const;
    //将视口坐标转换为世界坐标,需要至少渲染一帧后才能生效
    SVec3 ViewportToScene(
        const SVec2& InViewportPosition
        ,SVec3& OutWorldDirection
        ) const;
protected:
    //上一次渲染的相机参数
    SRenderCameraParameters LastParameters;
public:

    TWidgetAttribute<EViewportPaintMode> PaintMode=EViewportPaintMode::Scene;

    // TWidgetAttribute<bool> AxisVisible;

    TWidgetAttribute<SVec3> AxisOrigin;

    TWidgetAttribute<float> AxisScale=1.0f;

    TWidgetAttribute<SQuat> AxisRotation;

public:
    EAntiAliasingMethod AntiAliasingMethod=EAntiAliasingMethod::FXAA;

    //像素对象映射,用于鼠标拾取等功能
    //如果为空，则不启用像素对象映射
    //在设置为非空后，需要渲染两帧后才会生效
    //代码示例：
    //auto PixelObjectMap=NewWidget<RPixelObjectMap>(InParent);
    //Viewport->PixelObjectMap=PixelObjectMap;
    //等两帧后：
    //PixelObjectMap->QueryPixelObject(InMousePosition);
    TWidgetAttribute<TSharedObjectPtr<RPixelObjectMap>> PixelObjectMap;

    //获取像素对应的对象
    //只有在bEnablePixelObjectMap设为true两帧后有效，不会立即生效
    //返回值为nullptr表示没有找到对应的对象
    std::shared_ptr<CPixelObject> QueryPixelObject(const SIntPoint& InPosition);
protected:

};